﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MyAlbum.Model;
using System.Web.UI;
using System.Web.Routing;
using System.Web.UI.WebControls;
using System.ComponentModel;
//using StructureMap;
using PersonalAlbum.Controllers;
using System.Text;
using System.Web.Mvc.Html;
using System.Linq.Expressions;
using System.Reflection;
using System.IO;
using MyAlbum.Services;
using System.Security.Cryptography;
namespace PersonalAlbum
{
    public static class HelperMethods
    {
        public static void RenderPartialRequest(this HtmlHelper html, string viewDataKey)
        {
            if (ConfigManager.UseCache)
            {
                PartialRequest partial = html.ViewContext.ViewData.Eval(viewDataKey) as PartialRequest;
                if (partial != null)
                    partial.Invoke(html.ViewContext);
            }
            else
            {
                if (html.ViewContext.ViewData.ContainsKey(viewDataKey))
                {
                    html.RenderPartial(viewDataKey);
                }
            }
        }

        public static string LanguageDirection(this HtmlHelper html)
        {
            return "<style type=\"text/css\">\r\nbody{\r\ndirection: " + (html.ViewData.Model as PersonalAlbumModel).TextDirection + ";\r\n}\r\n </style>";
        }
        public static string Scripts(this HtmlHelper html)
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(html.ScriptFile("scripts.js"));
            sb.AppendLine(html.ScriptFile("jquery-1.2.6.min.js"));
            sb.AppendLine(html.ScriptFile("jquery.validate.js"));
            sb.AppendLine(html.ScriptFile("additional-methods.js"));
            sb.AppendLine(html.ScriptFile("interface.js"));
            return sb.ToString();
        }
        public static string RSSLink(this HtmlHelper html)
        {
            var model = html.ViewData.Model as PersonalAlbumModel;
            string result = null;
            if (model.Configuration.ShowRSS)
            {
                TagBuilder tb = new TagBuilder("link");
                tb.MergeAttribute("rel", "alternate");
                tb.MergeAttribute("type", "application/rss+xml");
                tb.MergeAttribute("title", model.Configuration.SiteTitle);
                tb.MergeAttribute("href", ConfigManager.SiteUrl + "/RSS" + (model.Configuration.UseAspxExtensions ? ".aspx" : null));
                result = tb.ToString(TagRenderMode.SelfClosing);
            }
            return result;
        }
        public static string ScriptFile(this HtmlHelper html, string fileName)
        {
            return "<script src=\"" + html.AbsolutePath("Scripts/" + fileName) + "\" type=\"text/javascript\"></script>";
        }
        public static string GravatorLink(this HtmlHelper html, string email)
        {
            if (!string.IsNullOrEmpty(email))
            {
                MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
                byte[] hashedBytes = md5.ComputeHash(Encoding.UTF8.GetBytes(email));
                StringBuilder sb = new StringBuilder(hashedBytes.Length * 2);
                for (int i = 0; i < hashedBytes.Length; i++)
                {
                    sb.Append(hashedBytes[i].ToString("X2"));
                }
                email = sb.ToString().ToLower();
            }
            int size = 60;
            string imageUrl = "http://www.gravatar.com/avatar.php?gravatar_id=" + email + "&rating=G&size=" + size;
            return "<img width=\"" + size + "\" height=\"" + size + "\" alt=\"Gravator\" src=\"" + imageUrl + "\"/>";
        }
        public static string EntryImage(this HtmlHelper html, string imageName)
        {
            return html.EntryImage(imageName, null);
        }

        public static string EntryImage(this HtmlHelper html, string imageName, object htmlAttributes)
        {
            UrlHelper u = new UrlHelper(html.ViewContext.RequestContext);
            imageName = u.Content(ConfigManager.ImagesPath + "/" + imageName);
            return html.Image(imageName, htmlAttributes);
        }

        public static string EntryUrl(this UrlHelper url, string imageName)
        {
            return url.Content(ConfigManager.ImagesPath + "/" + imageName);
        }
        /// <summary>
        /// Render a tooltip view
        /// </summary>
        /// <param name="html"></param>
        /// <param name="configName"></param>
        /// <returns></returns>
        public static string TooltipView(this HtmlHelper html, string configName)
        {
            var model = ((PersonalAlbumModel)html.ViewData.Model);
            string result = null;
            if (model.Configuration.ShowTooltips)
            {
                if (model.User.AllowActions())
                {
                    var configs = model.Configuration.Items;
                    if (configs != null)
                    {
                        var c = configs.FirstOrDefault(s => s.Name == configName);
                        if (c != null)
                        {
                            string targetId = Guid.NewGuid().ToString("N");
                            StringBuilder sb = new StringBuilder();
                            sb.Append("<a href=\"javascript:void(0)\" id=\"");
                            sb.Append(targetId);
                            sb.AppendLine("\">");
                            sb.AppendLine(html.ThemeImage("tooltip.jpg"));
                            sb.AppendLine("</a>");
                            var id = Guid.NewGuid().ToString("N");
                            sb.Append("<div id=\"");
                            sb.Append(id);
                            sb.AppendLine("\" style=\"display:none\">");
                            sb.AppendLine("<div class=\"toolTipWrapper\">");
                            sb.AppendLine("<span class=\"toolTipName\">");
                            sb.Append(html.Encode(c.Name));
                            sb.AppendLine("</span><br/>");
                            sb.AppendLine("<span class=\"toolTipDescription\">");
                            sb.AppendLine(html.Encode(c.Description));
                            sb.AppendLine("</span></br>");
                            sb.AppendLine(c.ToHtml());
                            sb.Append("<br/>");
                            sb.Append(html.ActionLink<AdminController>(o => o.Config(), model.Localize("Config.View")));
                            sb.AppendLine("</div>");
                            sb.AppendLine("</div>");
                            sb.AppendLine("<script type=\"text/javascript\">");
                            sb.Append("$(\"#");
                            sb.Append(targetId);
                            sb.AppendLine("\").simpletip({");
                            //sb.Append("persistent:true,focus:true,");
                            sb.Append("content: document.getElementById('");
                            sb.Append(id);
                            sb.AppendLine("').innerHTML });");
                            sb.AppendLine("</script>");
                            result = sb.ToString();
                        }
                    }
                }
            }
            return result;
        }
        ///// <summary>
        ///// Generates a tool tip with image for the required config name
        ///// </summary>
        ///// <param name="html"></param>
        ///// <param name="configName"></param>
        ///// <returns></returns>
        //public static string Tooltip2(this HtmlHelper html, string configName)
        //{
        //    string result = null;
        //    if (ConfigManager.ShowTooltips)
        //    {
        //        if (UserManager.AllowActions)
        //        {
        //            var configs = html.ViewData["conf igs"] as List<ConfigItem>;
        //            if (configs != null)
        //            {
        //                var c = configs.FirstOrDefault(s => s.Name == configName);
        //                if (c != null)
        //                {
        //                    UrlHelper u = new UrlHelper(html.ViewContext.RequestContext);
        //                    var targetId = Guid.NewGuid().ToString("N");
        //                    StringBuilder sb = new StringBuilder();
        //                    sb.Append("<a href=\"javascript:void(0)\" id=\"");
        //                    sb.Append(targetId);
        //                    sb.AppendLine("\">");
        //                    sb.AppendLine(html.ThemeImage("tooltip.jpg"));
        //                    sb.AppendLine("</a>");
        //                    var id = Guid.NewGuid().ToString("N");
        //                    sb.Append("<div id=\"");
        //                    sb.Append(id);
        //                    sb.AppendLine("\" style=\"display:none\">");
        //                    sb.AppendLine("<div class=\"toolTipWrapper\">");
        //                    sb.Append("<form method=\"POST\" action=\"");
        //                    sb.Append(u.Action("UpdateConfig", "Admin"));
        //                    sb.AppendLine("\">");
        //                    sb.Append(html.Hidden("returnUrl", HttpContext.Current.Request.RawUrl));
        //                    //the following line is needed for the update on checkbox will work
        //                    sb.Append(html.Hidden(html.Encode(c.Name) + "_description", c.Description));


        //                    sb.Append(html.AntiForgeryToken());
        //                    sb.AppendLine("<fieldset>");
        //                    sb.AppendLine("<span class=\"toolTipName\">");
        //                    sb.Append(html.Encode(c.Name));
        //                    sb.AppendLine("</span><br/>");
        //                    sb.AppendLine("<span class=\"toolTipDescription\">");
        //                    sb.AppendLine(html.Encode(c.Description));
        //                    sb.AppendLine("</span></br>");
        //                    sb.AppendLine(c.ToString());
        //                    sb.Append("<br/><input type=\"submit\" value=\"");
        //                    sb.Append(ObjectFactory.GetInstance<ILang uageService>().GetText("Config.Save"));
        //                    sb.Append("\">");
        //                    sb.AppendLine("</fieldset></form></div>");
        //                    sb.AppendLine("</div>");
        //                    sb.AppendLine("<script type=\"text/javascript\">");
        //                    sb.Append("$(\"#");
        //                    sb.Append(targetId);
        //                    sb.AppendLine("\").simpletip({");
        //                    //sb.Append("persistent:true,focus:true,");
        //                    sb.Append("content: document.getElementById('");
        //                    sb.Append(id);
        //                    sb.AppendLine("').innerHTML });");
        //                    sb.AppendLine("</script>");
        //                    result = sb.ToString();
        //                }
        //            }
        //        }
        //    }
        //    return result;
        //}


        //        public static string Popup(this HtmlHelper html, string id)
        //        {
        //            ILanguageService lang = ObjectFactory.GetInstance<ILanguageService>();
        //            UrlHelper u = new UrlHelper(html.ViewContext.RequestContext);
        //            StringBuilder sb = new StringBuilder();

        //            var targetId = Guid.NewGuid().ToString("N");
        //            HtmlTextWriter writer = new HtmlTextWriter(new StringWriter(sb));
        //            writer.AddAttribute(HtmlTextWriterAttribute.Href, "javascript:void(0)");
        //            writer.AddAttribute(HtmlTextWriterAttribute.Onclick, "$('#" + targetId + "').show()");
        //            writer.AddAttribute(HtmlTextWriterAttribute.Id, targetId + "Open");
        //            writer.RenderBeginTag(HtmlTextWriterTag.A);
        //            writer.Write(html.ThemeImage("tooltip.jpg"));
        //            writer.RenderEndTag();//a

        //            writer.AddAttribute(HtmlTextWriterAttribute.Class, "window");
        //            writer.AddAttribute(HtmlTextWriterAttribute.Id, targetId);
        //            writer.RenderBeginTag(HtmlTextWriterTag.Div);

        //            writer.AddStyleAttribute(HtmlTextWriterStyle.BackgroundImage, "url(" + html.ThemeItem("window_top_end.png") + ")");
        //            writer.AddAttribute(HtmlTextWriterAttribute.Class, "windowTop");
        //            writer.AddAttribute(HtmlTextWriterAttribute.Id, targetId + "Top");
        //            writer.RenderBeginTag(HtmlTextWriterTag.Div);

        //            writer.AddStyleAttribute(HtmlTextWriterStyle.BackgroundImage, "url(" + html.ThemeItem("window_top_start.png") + ")");
        //            writer.AddAttribute(HtmlTextWriterAttribute.Class, "windowTopContent");
        //            writer.AddAttribute(HtmlTextWriterAttribute.Id, targetId + "TopContent");
        //            writer.RenderBeginTag(HtmlTextWriterTag.Div);
        //            writer.WriteEncodedText(c.Name);
        //            writer.RenderEndTag();//div

        //            writer.AddAttribute(HtmlTextWriterAttribute.Class, "windowClose");
        //            writer.AddAttribute(HtmlTextWriterAttribute.Src, html.ThemeItem("window_close.jpg"));
        //            writer.AddAttribute(HtmlTextWriterAttribute.Id, targetId + "Close");
        //            writer.AddAttribute(HtmlTextWriterAttribute.Onclick, "$('#" + targetId + "').hide()");
        //            writer.AddAttribute(HtmlTextWriterAttribute.Alt, Model.Localize("Close"));
        //            writer.RenderBeginTag(HtmlTextWriterTag.Img);
        //            writer.RenderEndTag();//img

        //            writer.RenderEndTag();//div top


        //            writer.AddStyleAttribute(HtmlTextWriterStyle.BackgroundImage, "url(" + html.ThemeItem("window_bottom_end.png") + ")");
        //            writer.AddAttribute(HtmlTextWriterAttribute.Class, "windowBottom");
        //            writer.AddAttribute(HtmlTextWriterAttribute.Id, targetId + "Bottom");
        //            writer.RenderBeginTag(HtmlTextWriterTag.Div);

        //            writer.AddStyleAttribute(HtmlTextWriterStyle.BackgroundImage, "url(" + html.ThemeItem("window_bottom_start.png") + ")");
        //            writer.AddAttribute(HtmlTextWriterAttribute.Class, "windowBottomContent");
        //            writer.AddAttribute(HtmlTextWriterAttribute.Id, targetId + "BottomContent");
        //            writer.RenderBeginTag(HtmlTextWriterTag.Div);
        //            writer.Write("&nbsp;");
        //            writer.RenderEndTag();//div Bottom
        //            writer.RenderEndTag();//div BottomContent

        //            writer.AddAttribute(HtmlTextWriterAttribute.Class, "windowContent");
        //            writer.AddAttribute(HtmlTextWriterAttribute.Id, targetId + "Content");
        //            writer.RenderBeginTag(HtmlTextWriterTag.Div);

        //            writer.AddAttribute("action", u.Action("UpdateConfig", "Admin"));
        //            writer.AddAttribute("method", "post");
        //            writer.RenderBeginTag(HtmlTextWriterTag.Form);
        //            writer.Write(html.Hidden("returnUrl", HttpContext.Current.Request.RawUrl));

        //            //the following line is needed for the update on checkbox will work
        //            writer.Write(html.Hidden(html.Encode(c.Name) + "_description", c.Description));
        //            writer.Write(html.AntiForgeryToken());
        //            writer.RenderBeginTag(HtmlTextWriterTag.Fieldset);
        //            writer.AddAttribute(HtmlTextWriterAttribute.Class, "toolTipName");
        //            writer.RenderBeginTag(HtmlTextWriterTag.Span);
        //            writer.Write(html.Encode(c.Name));
        //            writer.RenderEndTag();//span
        //            writer.WriteBreak();

        //            writer.AddAttribute(HtmlTextWriterAttribute.Class, "toolTipDescription");
        //            writer.RenderBeginTag(HtmlTextWriterTag.Span);
        //            writer.Write(html.Encode(c.Description));
        //            writer.RenderEndTag();//span
        //            writer.WriteBreak();
        //            sb.AppendLine(c.ToString());
        //            writer.WriteBreak();
        //            writer.AddAttribute(HtmlTextWriterAttribute.Type, "submit");
        //            writer.AddAttribute(HtmlTextWriterAttribute.Value, Model.Localize("Config.Save"));
        //            writer.RenderBeginTag(HtmlTextWriterTag.Input);
        //            writer.RenderEndTag();//input submit

        //            writer.RenderEndTag();//fieldset

        //            writer.RenderEndTag();//form

        //            writer.RenderEndTag();//div contet

        //            writer.AddAttribute(HtmlTextWriterAttribute.Class, "windowResize");
        //            writer.AddAttribute(HtmlTextWriterAttribute.Src, html.ThemeItem("window_resize.gif"));
        //            writer.AddAttribute(HtmlTextWriterAttribute.Id, targetId + "Resize");
        //            writer.AddAttribute(HtmlTextWriterAttribute.Alt, string.Empty);
        //            writer.RenderBeginTag(HtmlTextWriterTag.Img);
        //            writer.RenderEndTag();//img

        //            writer.RenderEndTag();//div

        //            sb.Append(@" <script type=""text/javascript"">
        //<!--
        //$(document).ready(
        //	function()
        //	{
        //		$('#" + targetId + @"').Resizable(
        //			{
        //				minWidth: 200,
        //				minHeight: 60,
        //				maxWidth: 700,
        //				maxHeight: 400,
        //				dragHandle: '#" + targetId + @"Top',
        //				handlers: {
        //					se: '#" + targetId + @"Resize'
        //				},
        //				onResize : function(size, position) {
        //					$('#" + targetId + @"Bottom, #" + targetId + @"BottomContent').css('height', size.height-33 + 'px');
        //					var windowContentEl = $('#" + targetId + @"Content').css('width', size.width - 25 + 'px');
        //					if (!document.getElementById('" + targetId + @"').isMinimized) {
        //						windowContentEl.css('height', size.height - 48 + 'px');
        //					}
        //				}
        //			}
        //		);
        //	}
        //);
        //-->
        //</script>");
        //            result = sb.ToString();
        //        }

        /// <summary>
        /// Generates a tool tip with image for the required config name
        /// </summary>
        /// <param name="html"></param>
        /// <param name="configName"></param>
        /// <returns></returns>
        public static string Tooltip(this HtmlHelper html, string configName)
        {
            string result = null;
            var model = ((PersonalAlbumModel)html.ViewData.Model);
            if (model.Configuration.ShowTooltips)
            {
                if (model.User.AllowActions())
                {
                    var configs = model.Configuration.Items;
                    if (configs != null)
                    {
                        var c = configs.FirstOrDefault(s => s.Name == configName);
                        if (c != null)
                        {
                            UrlHelper u = new UrlHelper(html.ViewContext.RequestContext);
                            StringBuilder sb = new StringBuilder();

                            var targetId = Guid.NewGuid().ToString("N");
                            HtmlTextWriter writer = new HtmlTextWriter(new StringWriter(sb));
                            writer.AddAttribute(HtmlTextWriterAttribute.Href, "javascript:void(0)");
                            writer.AddAttribute(HtmlTextWriterAttribute.Onclick, "$('#" + targetId + "').show()");
                            writer.AddAttribute(HtmlTextWriterAttribute.Id, targetId + "Open");
                            writer.RenderBeginTag(HtmlTextWriterTag.A);
                            writer.Write(html.ThemeImage("tooltip.jpg"));
                            writer.RenderEndTag();//a

                            writer.AddAttribute(HtmlTextWriterAttribute.Class, "window");
                            writer.AddAttribute(HtmlTextWriterAttribute.Id, targetId);
                            writer.RenderBeginTag(HtmlTextWriterTag.Div);

                            writer.AddStyleAttribute(HtmlTextWriterStyle.BackgroundImage, "url(" + html.ThemeItem("window_top_end.png") + ")");
                            writer.AddAttribute(HtmlTextWriterAttribute.Class, "windowTop");
                            writer.AddAttribute(HtmlTextWriterAttribute.Id, targetId + "Top");
                            writer.RenderBeginTag(HtmlTextWriterTag.Div);

                            writer.AddStyleAttribute(HtmlTextWriterStyle.BackgroundImage, "url(" + html.ThemeItem("window_top_start.png") + ")");
                            writer.AddAttribute(HtmlTextWriterAttribute.Class, "windowTopContent");
                            writer.AddAttribute(HtmlTextWriterAttribute.Id, targetId + "TopContent");
                            writer.RenderBeginTag(HtmlTextWriterTag.Div);
                            writer.WriteEncodedText(c.Name);
                            writer.RenderEndTag();//div

                            writer.AddAttribute(HtmlTextWriterAttribute.Class, "windowClose");
                            writer.AddAttribute(HtmlTextWriterAttribute.Src, html.ThemeItem("window_close.jpg"));
                            writer.AddAttribute(HtmlTextWriterAttribute.Id, targetId + "Close");
                            writer.AddAttribute(HtmlTextWriterAttribute.Onclick, "$('#" + targetId + "').hide()");
                            writer.AddAttribute(HtmlTextWriterAttribute.Alt, model.Localize("Close"));
                            writer.RenderBeginTag(HtmlTextWriterTag.Img);
                            writer.RenderEndTag();//img

                            writer.RenderEndTag();//div top


                            writer.AddStyleAttribute(HtmlTextWriterStyle.BackgroundImage, "url(" + html.ThemeItem("window_bottom_end.png") + ")");
                            writer.AddAttribute(HtmlTextWriterAttribute.Class, "windowBottom");
                            writer.AddAttribute(HtmlTextWriterAttribute.Id, targetId + "Bottom");
                            writer.RenderBeginTag(HtmlTextWriterTag.Div);

                            writer.AddStyleAttribute(HtmlTextWriterStyle.BackgroundImage, "url(" + html.ThemeItem("window_bottom_start.png") + ")");
                            writer.AddAttribute(HtmlTextWriterAttribute.Class, "windowBottomContent");
                            writer.AddAttribute(HtmlTextWriterAttribute.Id, targetId + "BottomContent");
                            writer.RenderBeginTag(HtmlTextWriterTag.Div);
                            writer.Write("&nbsp;");
                            writer.RenderEndTag();//div Bottom
                            writer.RenderEndTag();//div BottomContent

                            writer.AddAttribute(HtmlTextWriterAttribute.Class, "windowContent");
                            writer.AddAttribute(HtmlTextWriterAttribute.Id, targetId + "Content");
                            writer.RenderBeginTag(HtmlTextWriterTag.Div);

                            writer.AddAttribute("action", u.Action("UpdateConfig", "Admin"));
                            writer.AddAttribute("method", "post");
                            writer.RenderBeginTag(HtmlTextWriterTag.Form);
                            writer.Write(html.Hidden("returnUrl", HttpContext.Current.Request.RawUrl));

                            //the following line is needed for the update on checkbox will work
                            writer.Write(html.Hidden(html.Encode(c.Name) + "_description", c.Description));
                            writer.Write(html.AntiForgeryToken());
                            writer.RenderBeginTag(HtmlTextWriterTag.Fieldset);
                            writer.AddAttribute(HtmlTextWriterAttribute.Class, "toolTipName");
                            writer.RenderBeginTag(HtmlTextWriterTag.Span);
                            writer.Write(html.Encode(c.Name));
                            writer.RenderEndTag();//span
                            writer.WriteBreak();

                            writer.AddAttribute(HtmlTextWriterAttribute.Class, "toolTipDescription");
                            writer.RenderBeginTag(HtmlTextWriterTag.Span);
                            writer.Write(html.Encode(c.Description));
                            writer.RenderEndTag();//span
                            writer.WriteBreak();
                            sb.AppendLine(c.ToHtml());
                            writer.WriteBreak();
                            writer.AddAttribute(HtmlTextWriterAttribute.Type, "submit");
                            writer.AddAttribute(HtmlTextWriterAttribute.Value, model.Localize("Config.Save"));
                            writer.RenderBeginTag(HtmlTextWriterTag.Input);
                            writer.RenderEndTag();//input submit

                            writer.RenderEndTag();//fieldset

                            writer.RenderEndTag();//form

                            writer.RenderEndTag();//div contet

                            writer.AddAttribute(HtmlTextWriterAttribute.Class, "windowResize");
                            writer.AddAttribute(HtmlTextWriterAttribute.Src, html.ThemeItem("window_resize.gif"));
                            writer.AddAttribute(HtmlTextWriterAttribute.Id, targetId + "Resize");
                            writer.AddAttribute(HtmlTextWriterAttribute.Alt, string.Empty);
                            writer.RenderBeginTag(HtmlTextWriterTag.Img);
                            writer.RenderEndTag();//img

                            writer.RenderEndTag();//div

                            sb.Append(@" <script type=""text/javascript"">
<!--
$(document).ready(
	function()
	{
		$('#" + targetId + @"').Resizable(
			{
				minWidth: 200,
				minHeight: 60,
				maxWidth: 700,
				maxHeight: 400,
				dragHandle: '#" + targetId + @"Top',
				handlers: {
					se: '#" + targetId + @"Resize'
				},
				onResize : function(size, position) {
					$('#" + targetId + @"Bottom, #" + targetId + @"BottomContent').css('height', size.height-33 + 'px');
					var windowContentEl = $('#" + targetId + @"Content').css('width', size.width - 25 + 'px');
					if (!document.getElementById('" + targetId + @"').isMinimized) {
						windowContentEl.css('height', size.height - 48 + 'px');
					}
				}
			}
		);
	}
);
-->
</script>");
                            result = sb.ToString();
                        }
                    }
                }
            }
            return result;
        }

        /// <summary>
        /// Returns the absolute url for the specified file
        /// in the directory of the current theme
        /// </summary>
        /// <param name="html"></param>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public static string ThemeItem(this HtmlHelper html, string fileName)
        {
            return ConfigManager.SiteUrl + "/Content/Themes/" +
               ConfigManager.ThemePath + "/" +
               (fileName != null ? fileName.TrimStart('/') : null);
        }


        /// <summary>
        /// Generate an image tag for a image in the current theme directory
        /// </summary>
        /// <param name="html"></param>
        /// <param name="imageName"></param>
        /// <returns></returns>
        public static string ThemeImage(this HtmlHelper html, string imageName)
        {
            return ThemeImage(html, imageName, null);

        }


        /// <summary>
        /// Render an image from the current theme directory
        /// </summary>
        /// <param name="html"></param>
        /// <param name="imageName"></param>
        /// <param name="htmlAttributes"></param>
        /// <returns></returns>
        public static string ThemeImage(this HtmlHelper html, string imageName, object htmlAttributes)
        {
            Dictionary<string, string> dic = null;
            if (htmlAttributes != null)
            {
                dic = new Dictionary<string, string>();
                foreach (PropertyDescriptor item in TypeDescriptor.GetProperties(htmlAttributes))
                {
                    dic.Add(item.Name, item.GetValue(htmlAttributes).ToString());
                }
            }
            return ThemeImage(html, imageName, dic, null);

        }

        /// <summary>
        /// Render an image from the current theme directory
        /// </summary>
        /// <param name="html"></param>
        /// <param name="imageName"></param>
        /// <param name="htmlAttributes"></param>
        /// <returns></returns>
        public static string ThemeImage(this HtmlHelper html, string imageName, Dictionary<string, string> htmlAttributes, Dictionary<string, string> style)
        {
            var builder = new TagBuilder("img");
            bool altFound = false;
            if (htmlAttributes != null)
            {
                foreach (var item in htmlAttributes.Keys)
                {
                    if (item.Equals("alt", StringComparison.InvariantCultureIgnoreCase))
                    {
                        altFound = true;
                    }
                    builder.MergeAttribute(item, htmlAttributes[item]);
                }
            }
            if (!altFound)
            {
                builder.MergeAttribute("alt", imageName);
            }
            builder.MergeAttribute("src", ThemeItem(html, imageName));
            return builder.ToString(TagRenderMode.SelfClosing);

        }

        /// <summary>
        /// Gets the absolute url for the specified file
        /// </summary>
        /// <param name="html"></param>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public static string AbsolutePath(this HtmlHelper html, string fileName)
        {
            return ConfigManager.SiteUrl + "/" +
                (fileName != null ? fileName.TrimStart('/') : null);
        }

        /// <summary>
        /// Render an image for an album preview, if non 
        /// is specified, the default thumb image will be used
        /// </summary>
        /// <param name="html"></param>
        /// <param name="imageUrl">A custom image relative url</param>
        /// <returns></returns>
        public static string AlbumImage(this HtmlHelper html, string imageUrl)
        {
            if (string.IsNullOrEmpty(imageUrl))
            {
                return ThemeImage(html, "album.gif");
            }
            else
            {
                var path = ConfigManager.ImagesPath.TrimEnd('/') + "/" + imageUrl.TrimStart('/');
                return html.Image(path, ((PersonalAlbumModel)html.ViewData.Model).Localize("View"), new Dictionary<string, object>() { { "class", "albumImage" } });
            }
        }


        public static string Image(this HtmlHelper helper, string imageRelativeUrl)
        {
            return helper.Image(imageRelativeUrl, null, ((IDictionary<string, object>)null));
        }


        public static string Image(this HtmlHelper helper, string imageRelativeUrl, IDictionary<string, object> htmlAttributes)
        {
            return helper.Image(imageRelativeUrl, null, htmlAttributes);
        }

        public static string Image(this HtmlHelper helper, string imageRelativeUrl, object htmlAttributes)
        {
            return helper.Image(imageRelativeUrl, null, ((IDictionary<string, object>)new RouteValueDictionary(htmlAttributes)));
        }
        public static string Image(this HtmlHelper helper, string imageRelativeUrl, string alt)
        {
            return helper.Image(imageRelativeUrl, alt, ((IDictionary<string, object>)null));
        }

        public static string Image(this HtmlHelper helper, string imageRelativeUrl, string alt, IDictionary<string, object> htmlAttributes)
        {
            if (string.IsNullOrEmpty(imageRelativeUrl))
            {
                throw new ArgumentNullException("imageRelativeUrl");
            }
            UrlHelper url = new UrlHelper(helper.ViewContext.RequestContext);
            return Image(url.Content(imageRelativeUrl), alt, htmlAttributes).ToString(TagRenderMode.SelfClosing);
        }

        public static string Image(this HtmlHelper helper, string imageRelativeUrl, string alt, object htmlAttributes)
        {
            return helper.Image(imageRelativeUrl, alt, ((IDictionary<string, object>)new RouteValueDictionary(htmlAttributes)));
        }







        public static TagBuilder Image(string imageUrl, string alt, IDictionary<string, object> htmlAttributes)
        {
            if (string.IsNullOrEmpty(imageUrl))
            {
                throw new ArgumentNullException("imageUrl");
            }
            TagBuilder imageTag = new TagBuilder("img");
            if (!string.IsNullOrEmpty(imageUrl))
            {
                imageTag.MergeAttribute("src", imageUrl);
            }
            if (!string.IsNullOrEmpty(alt))
            {
                imageTag.MergeAttribute("alt", alt);
            }
            imageTag.MergeAttributes<string, object>(htmlAttributes, true);
            if (imageTag.Attributes.ContainsKey("alt") && !imageTag.Attributes.ContainsKey("title"))
            {
                imageTag.MergeAttribute("title", (imageTag.Attributes["alt"] ?? "").ToString());
            }
            return imageTag;
        }


        /// <summary>
        /// Render an image for a section preview, if non 
        /// is specified, the default thumb image will be used
        /// </summary>
        /// <param name="html"></param>
        /// <param name="imageUrl">A custom image relative url</param>
        /// <returns></returns>
        public static string SectionImage(this HtmlHelper html, string imageUrl)
        {
            if (string.IsNullOrEmpty(imageUrl))
            {
                return ThemeImage(html, "section.gif", new Dictionary<string, string>() { { "class", "sectionImage" } }, null);
            }
            else
            {
                var path = ConfigManager.ImagesPath.TrimEnd('/') + "/" + imageUrl.TrimStart('/');
                return html.Image(path, ((PersonalAlbumModel)html.ViewData.Model).Localize("View"), new Dictionary<string, object>() { { "class", "sectionImage" } });
            }
        }

        /// <summary>
        /// Render an image from the images directory, if the imageUrl is empty,
        /// the defaultUrl will be used
        /// </summary>
        /// <param name="html"></param>
        /// <param name="imageUrl"></param>
        /// <param name="defaultUrl"></param>
        /// <returns></returns>
        private static string ImageOrDefault(HtmlHelper html, string imageUrl, string defaultUrl)
        {
            string path = null;
            if (!string.IsNullOrEmpty(imageUrl))
            {
                path = ConfigManager.ImagesPath.TrimEnd('/') + "/" + imageUrl.TrimStart('/');
            }
            else
            {
                if (defaultUrl != null)
                {
                    path = ConfigManager.ImagesPath.TrimEnd('/') + "/" + defaultUrl.TrimStart('/');
                }
            }
            if (path != null)
            {
                return html.Image(path, ((PersonalAlbumModel)html.ViewData.Model).Localize("View"));
            }
            else
            {
                return null;
            }

        }

        /// <summary>
        /// Render an item to html
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public static string Render(this Entry item)
        {
            return Render(item, null, null);
        }

        /// <summary>
        /// Render an item to html
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public static string Render(this Entry item, object htmlAttributes, object styleAttributes)
        {
            return RenderInternal(item, htmlAttributes, styleAttributes, false);
        }

        /// <summary>
        /// Render an item to html
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public static string Render(this Entry item, Dictionary<string, string> htmlAttributes, Dictionary<string, string> styleAttributes)
        {
            return RenderInternal(item, htmlAttributes, styleAttributes, false);
        }


        /// <summary>
        /// Render an item to html in thumb mode
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public static string RenderThumb(this Entry item)
        {
            return RenderThumb(item, null, null);
        }

        /// <summary>
        /// Render an item to html in thumb mode
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public static string RenderThumb(this Entry item, object htmlAttributes, object styleAttributes)
        {
            return RenderInternal(item, htmlAttributes, styleAttributes, true);
        }

        /// <summary>
        /// Render an item to html in thumb mode
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public static string RenderThumb(this Entry item, Dictionary<string, string> htmlAttributes, Dictionary<string, string> styleAttributes)
        {
            return RenderInternal(item, htmlAttributes, styleAttributes, true);
        }


        private static string RenderInternal(Entry item, object htmlAttributes, object styleAttributes, bool thumb)
        {
            var d1 = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
            foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(htmlAttributes))
            {
                d1.Add(descriptor.Name, descriptor.GetValue(htmlAttributes).ToString());
            }

            var d2 = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
            foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(styleAttributes))
            {
                d2.Add(descriptor.Name, descriptor.GetValue(styleAttributes).ToString());
            }

            return RenderInternal(item, d1, d2, thumb);
        }

        private static string RenderInternal(Entry item, Dictionary<string, string> htmlAttributes, Dictionary<string, string> styleAttributes, bool thumb)
        {
            var entryType = (EntryTypes)Enum.Parse(typeof(EntryTypes), item.EntryType.ToString());
            string html;
            //for movies thumb we'll show the thumb image if available, or the default
            //for that movie type
            switch (entryType)
            {
                case EntryTypes.Image:
                    html = RenderImageEntry(item, htmlAttributes, styleAttributes, thumb);
                    break;
                case EntryTypes.QuickTimeVideo:
                    if (thumb)
                    {
                        if (string.IsNullOrEmpty(item.ThumbUri))
                        {
                            item.ThumbUri = "QuickTime.jpg";
                            item.ThumbWidth = ConfigManager.ThumbDefaultWidth;
                            item.ThumbHeight = ConfigManager.ThumbDefaultHeight;
                        }
                        html = RenderImageEntry(item, htmlAttributes, styleAttributes, thumb);
                    }
                    else
                    {
                        html = RenderQuickTimeMovie(item, htmlAttributes, styleAttributes, thumb);
                    }
                    break;
                case EntryTypes.MediaPlayerVideo:
                    if (thumb)
                    {
                        if (string.IsNullOrEmpty(item.ThumbUri))
                        {
                            item.ThumbUri = "MediaPlayer.jpg";
                            item.ThumbWidth = ConfigManager.ThumbDefaultWidth;
                            item.ThumbHeight = ConfigManager.ThumbDefaultHeight;
                        }
                        html = RenderImageEntry(item, htmlAttributes, styleAttributes, thumb);
                    }
                    else
                    {
                        html = RenderMediaPlayerMovie(item, htmlAttributes, styleAttributes, thumb);
                    }
                    break;
                case EntryTypes.YouTubeVideo:
                    if (thumb)
                    {
                        if (string.IsNullOrEmpty(item.ThumbUri))
                        {
                            item.ThumbUri = "YouTube.jpg";
                            item.ThumbWidth = ConfigManager.ThumbDefaultWidth;
                            item.ThumbHeight = ConfigManager.ThumbDefaultHeight;
                        }
                        html = RenderImageEntry(item, htmlAttributes, styleAttributes, thumb);
                    }
                    else
                    {
                        html = RenderYouTubeMovie(item, htmlAttributes, styleAttributes, thumb);
                    }
                    break;
                default:
                    html = null;
                    break;
            }

            return html;
        }

        private static string RenderMediaPlayerMovie(Entry item, Dictionary<string, string> htmlAttributes, Dictionary<string, string> styleAttributes, bool thumb)
        {
            string uri = Uri.IsWellFormedUriString(item.Uri, UriKind.Absolute) ? item.Uri :
                ConfigManager.SiteUrl + "/" +
               ConfigManager.ImagesPath.TrimStart(new char[] { '/', '~' }) + "/" + item.Uri.TrimStart('/');
            HtmlTextWriter writer = new HtmlTextWriter(new StringWriter());
            writer.AddAttribute("classid", "CLSID:22d6f312-b0f6-11d0-94ab-0080c74c7e95");
            if (item.Width > 0)
            {
                writer.AddAttribute(HtmlTextWriterAttribute.Width, item.Width.ToString());
            }
            if (item.Height > 0)
            {
                writer.AddAttribute(HtmlTextWriterAttribute.Height, item.Height.ToString());
            }
            writer.AddAttribute("codebase", "http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=5,1,52,701");
            writer.AddAttribute(HtmlTextWriterAttribute.Type, "application/x-oleobject");
            writer.RenderBeginTag(HtmlTextWriterTag.Object);


            writer.AddAttribute(HtmlTextWriterAttribute.Name, "fileName");
            writer.AddAttribute(HtmlTextWriterAttribute.Value, uri);
            writer.RenderBeginTag(HtmlTextWriterTag.Param);
            writer.RenderEndTag();//param

            writer.AddAttribute(HtmlTextWriterAttribute.Name, "animationatStart");
            writer.AddAttribute(HtmlTextWriterAttribute.Value, "true");
            writer.RenderBeginTag(HtmlTextWriterTag.Param);
            writer.RenderEndTag();//param

            writer.AddAttribute(HtmlTextWriterAttribute.Name, "transparentatStart");
            writer.AddAttribute(HtmlTextWriterAttribute.Value, "true");
            writer.RenderBeginTag(HtmlTextWriterTag.Param);
            writer.RenderEndTag();//param

            writer.AddAttribute(HtmlTextWriterAttribute.Name, "showControls");
            writer.AddAttribute(HtmlTextWriterAttribute.Value, "true");
            writer.RenderBeginTag(HtmlTextWriterTag.Param);
            writer.RenderEndTag();//param

            writer.AddAttribute(HtmlTextWriterAttribute.Name, "loop");
            writer.AddAttribute(HtmlTextWriterAttribute.Value, "false");
            writer.RenderBeginTag(HtmlTextWriterTag.Param);
            writer.RenderEndTag();//param

            writer.AddAttribute(HtmlTextWriterAttribute.Name, "autoStart");
            writer.AddAttribute(HtmlTextWriterAttribute.Value, "false");
            writer.RenderBeginTag(HtmlTextWriterTag.Param);
            writer.RenderEndTag();//param

            writer.AddAttribute(HtmlTextWriterAttribute.Type, "application/x-mplayer2");
            writer.AddAttribute("pluginspage", "http://microsoft.com/windows/mediaplayer/en/download/");
            writer.AddAttribute("displaysize", "4");
            writer.AddAttribute("autosize", "-1");
            writer.AddAttribute(HtmlTextWriterAttribute.Src, uri);
            if (item.Width > 0)
            {
                writer.AddAttribute(HtmlTextWriterAttribute.Width, item.Width.ToString());
            }
            if (item.Height > 0)
            {
                writer.AddAttribute(HtmlTextWriterAttribute.Height, item.Height.ToString());
            }
            writer.AddAttribute("autostart", "false");
            writer.AddAttribute("showcontrols", "true");
            writer.AddAttribute("loop", "false");
            writer.RenderBeginTag(HtmlTextWriterTag.Embed);
            writer.RenderEndTag();//embed


            writer.RenderEndTag();//object

            return writer.InnerWriter.ToString();
        }

        private static string RenderYouTubeMovie(Entry item, Dictionary<string, string> htmlAttributes, Dictionary<string, string> styleAttributes, bool thumb)
        {
            string uri = Uri.IsWellFormedUriString(item.Uri, UriKind.Absolute) ? item.Uri :
              ConfigManager.SiteUrl + "/" +
             ConfigManager.ImagesPath.TrimStart(new char[] { '/', '~' }) + "/" + item.Uri.TrimStart('/');
            HtmlTextWriter writer = new HtmlTextWriter(new StringWriter());
            if (item.Width > 0)
            {
                writer.AddAttribute(HtmlTextWriterAttribute.Width, item.Width.ToString());
            }
            if (item.Height > 0)
            {
                writer.AddAttribute(HtmlTextWriterAttribute.Height, item.Height.ToString());
            }
            writer.RenderBeginTag(HtmlTextWriterTag.Object);

            writer.AddAttribute(HtmlTextWriterAttribute.Name, "movie");
            writer.AddAttribute(HtmlTextWriterAttribute.Value, uri);
            writer.RenderBeginTag(HtmlTextWriterTag.Param);
            writer.RenderEndTag();//param

            writer.AddAttribute(HtmlTextWriterAttribute.Name, "allowFullScreen");
            writer.AddAttribute(HtmlTextWriterAttribute.Value, "true");
            writer.RenderBeginTag(HtmlTextWriterTag.Param);
            writer.RenderEndTag();//param

            writer.AddAttribute(HtmlTextWriterAttribute.Name, "allowscriptaccess");
            writer.AddAttribute(HtmlTextWriterAttribute.Value, "always");
            writer.RenderBeginTag(HtmlTextWriterTag.Param);
            writer.RenderEndTag();//param

            writer.AddAttribute(HtmlTextWriterAttribute.Src, uri);
            if (item.Width > 0)
            {
                writer.AddAttribute(HtmlTextWriterAttribute.Width, item.Width.ToString());
            }
            if (item.Height > 0)
            {
                writer.AddAttribute(HtmlTextWriterAttribute.Height, item.Height.ToString());
            }
            writer.AddAttribute(HtmlTextWriterAttribute.Type, "application/x-shockwave-flash");
            writer.AddAttribute("allowscriptaccess", "always");
            writer.AddAttribute("allowFullScreen", "true");
            writer.RenderBeginTag(HtmlTextWriterTag.Embed);
            writer.RenderEndTag();//embed


            writer.RenderEndTag();//object

            return writer.InnerWriter.ToString();
        }

        private static string RenderQuickTimeMovie(Entry item, Dictionary<string, string> htmlAttributes, Dictionary<string, string> styleAttributes, bool thumb)
        {
            string uri = Uri.IsWellFormedUriString(item.Uri, UriKind.Absolute) ? item.Uri :
               ConfigManager.SiteUrl + "/" +
               ConfigManager.ImagesPath.TrimStart(new char[] { '/', '~' }) + "/" + item.Uri.TrimStart('/');
            HtmlTextWriter writer = new HtmlTextWriter(new StringWriter());
            writer.AddAttribute("classid", "clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B");
            if (item.Width > 0)
            {
                writer.AddAttribute(HtmlTextWriterAttribute.Width, item.Width.ToString());
            }
            if (item.Height > 0)
            {
                writer.AddAttribute(HtmlTextWriterAttribute.Height, item.Height.ToString());
            }
            writer.AddAttribute("codebase", "http://www.apple.com/qtactivex/qtplugin.cab");
            writer.RenderBeginTag(HtmlTextWriterTag.Object);
            writer.AddAttribute(HtmlTextWriterAttribute.Name, "src");
            writer.AddAttribute(HtmlTextWriterAttribute.Value, uri);
            writer.RenderBeginTag(HtmlTextWriterTag.Param);
            writer.RenderEndTag();//param

            writer.AddAttribute(HtmlTextWriterAttribute.Name, "autoplay");
            writer.AddAttribute(HtmlTextWriterAttribute.Value, "false");
            writer.RenderBeginTag(HtmlTextWriterTag.Param);
            writer.RenderEndTag();//param

            writer.AddAttribute(HtmlTextWriterAttribute.Name, "controller");
            writer.AddAttribute(HtmlTextWriterAttribute.Value, "true");
            writer.RenderBeginTag(HtmlTextWriterTag.Param);
            writer.RenderEndTag();//param

            writer.AddAttribute(HtmlTextWriterAttribute.Name, "loop");
            writer.AddAttribute(HtmlTextWriterAttribute.Value, "false");
            writer.RenderBeginTag(HtmlTextWriterTag.Param);
            writer.RenderEndTag();//param

            writer.AddAttribute(HtmlTextWriterAttribute.Src, uri);
            if (item.Width > 0)
            {
                writer.AddAttribute(HtmlTextWriterAttribute.Width, item.Width.ToString());
            }
            if (item.Height > 0)
            {
                writer.AddAttribute(HtmlTextWriterAttribute.Height, item.Height.ToString());
            }
            writer.AddAttribute("autoplay", "false");
            //  writer.AddAttribute("controller", "true");
            writer.AddAttribute("loop", "false");
            writer.AddAttribute("pluginspage", "http://www.apple.com/quicktime/download/");
            writer.RenderBeginTag(HtmlTextWriterTag.Embed);
            writer.RenderEndTag();//embed


            writer.RenderEndTag();//object

            return writer.InnerWriter.ToString();
        }

        private static string RenderImageEntry(Entry item, Dictionary<string, string> htmlAttributes, Dictionary<string, string> styleAttributes, bool thumb)
        {
            TagBuilder builder = new TagBuilder("img");
            if (thumb)
            {
                if (item.ThumbWidth > 0)
                {
                    builder.MergeAttribute("width", item.ThumbWidth.ToString());
                }
                if (item.ThumbHeight > 0)
                {
                    builder.MergeAttribute("height", item.ThumbHeight.ToString());
                }
            }
            else
            {
                if (item.Width > 0)
                {
                    builder.MergeAttribute("width", item.Width.ToString());
                }
                if (item.Height > 0)
                {
                    builder.MergeAttribute("height", item.Height.ToString());
                }
            }
            if (htmlAttributes != null)
            {
                foreach (var key in htmlAttributes.Keys)
                {
                    builder.MergeAttribute(key, htmlAttributes[key]);
                }
            }

            if (styleAttributes != null)
            {
                StringBuilder sb = new StringBuilder();
                foreach (var key in styleAttributes.Keys)
                {
                    sb.Append(key + ":" + styleAttributes[key] + ";");
                }
                builder.MergeAttribute("style", sb.ToString());
            }
            builder.MergeAttribute("src", ConfigManager.SiteUrl + "/Content/Images/" + (thumb ? item.ThumbUri : item.Uri));
            builder.MergeAttribute("title", item.Title);
            builder.AddCssClass("entryImage");
            builder.MergeAttribute("alt", string.IsNullOrEmpty(item.Description) ? item.Title : item.Description);
            return builder.ToString(TagRenderMode.SelfClosing);
        }


        public static string RenderAjaxControl(UrlHelper url, string controller, string action)
        {
            string id = "a" + Guid.NewGuid().ToString("N");//xhtml1.0 does not allow id to start with a number
            string path = url.Action(action, controller);
            string s = "<div id=\"" + id + "\"></div>\r\n" +
            "<script type=\"text/javascript\">\r\n" +
            "$(document).ready(function(){\r\n" +
            "$.ajax({\r\n" +
                "url:'" + path + "',\r\n" +
                "success:function(t){\r\n" +
                "document.getElementById('" + id + "').innerHTML=t;\r\n" +
                "}\r\n" +//function
                "})\r\n" +//ajax
                "});\r\n" +//ready
                "</script>";
            return s;

        }

        public static MvcForm BeginForm<TController>(this HtmlHelper helper, Expression<Action<TController>> action) where TController : Controller
        {
            return helper.BeginForm<TController>(action, FormMethod.Post, ((IDictionary<string, object>)null));
        }
        public static MvcForm BeginForm<TController>(this HtmlHelper helper, Expression<Action<TController>> action, FormMethod method) where TController : Controller
        {
            return helper.BeginForm<TController>(action, method, ((IDictionary<string, object>)null));
        }
        public static MvcForm BeginForm<TController>(this HtmlHelper helper, Expression<Action<TController>> action, FormMethod method, IDictionary<string, object> htmlAttributes) where TController : Controller
        {
            TagBuilder tagBuilder = new TagBuilder("form");
            tagBuilder.MergeAttributes<string, object>(htmlAttributes);
            string formAction = helper.BuildUrlFromExpression<TController>(action);
            tagBuilder.MergeAttribute("action", formAction);
            tagBuilder.MergeAttribute("method", HtmlHelper.GetFormMethodString(method));
            helper.ViewContext.HttpContext.Response.Write(tagBuilder.ToString(TagRenderMode.StartTag));
            return new MvcForm(helper.ViewContext);
        }
        public static MvcForm BeginForm<TController>(this HtmlHelper helper, Expression<Action<TController>> action, FormMethod method, object htmlAttributes) where TController : Controller
        {
            return helper.BeginForm<TController>(action, method, ((IDictionary<string, object>)new RouteValueDictionary(htmlAttributes)));
        }

        public static string BuildUrlFromExpression<TController>(this HtmlHelper helper, Expression<Action<TController>> action) where TController : Controller
        {
            return LinkBuilder.BuildUrlFromExpression<TController>(helper.ViewContext, helper.RouteCollection, action);
        }

        public static string ActionLink<TController>(this HtmlHelper helper, Expression<Action<TController>> action, string linkText, object htmlAttributes) where TController : Controller
        {
            RouteValueDictionary routingValues = ExpressionHelper.GetRouteValuesFromExpression<TController>(action);
            return helper.RouteLink(linkText, routingValues, new RouteValueDictionary(htmlAttributes)).ToString();
        }

        public static string ActionLink<TController>(this HtmlHelper helper, Expression<Action<TController>> action, string linkText) where TController : Controller
        {
            return helper.ActionLink<TController>(action, linkText, null);
        }

    }

    public static class ExpressionHelper
    {
        // Methods
        private static void AddParameterValuesFromExpressionToDictionary(RouteValueDictionary rvd, MethodCallExpression call)
        {
            ParameterInfo[] parameters = call.Method.GetParameters();
            if (parameters.Length > 0)
            {
                for (int i = 0; i < parameters.Length; i++)
                {
                    Expression arg = call.Arguments[i];
                    object value = null;
                    ConstantExpression ce = arg as ConstantExpression;
                    if (ce != null)
                    {
                        value = ce.Value;
                    }
                    else
                    {
                        Expression<Func<object>> lambdaExpression = Expression.Lambda<Func<object>>(Expression.Convert(arg, typeof(object)), new ParameterExpression[0]);
                        value = lambdaExpression.Compile()();
                    }
                    rvd.Add(parameters[i].Name, value);
                }
            }
        }

        public static RouteValueDictionary GetRouteValuesFromExpression<TController>(Expression<Action<TController>> action) where TController : Controller
        {
            if (action == null)
            {
                throw new ArgumentNullException("action");
            }
            MethodCallExpression call = action.Body as MethodCallExpression;
            if (call == null)
            {
                throw new ArgumentNullException("action");
            }
            string controllerName = typeof(TController).Name;
            if (!controllerName.EndsWith("Controller", StringComparison.OrdinalIgnoreCase))
            {
                throw new ArgumentNullException("action");
            }
            controllerName = controllerName.Substring(0, controllerName.Length - "Controller".Length);
            if (controllerName.Length == 0)
            {
                throw new ArgumentNullException("action");
            }
            RouteValueDictionary rvd = new RouteValueDictionary();
            rvd.Add("Controller", controllerName);
            rvd.Add("Action", call.Method.Name);
            AddParameterValuesFromExpressionToDictionary(rvd, call);
            return rvd;
        }
    }

    public static class LinkBuilder
    {
        // Methods
        public static RouteValueDictionary BuildParameterValuesFromExpression(MethodCallExpression call)
        {
            RouteValueDictionary result = new RouteValueDictionary();
            ParameterInfo[] parameters = call.Method.GetParameters();
            if (parameters.Length > 0)
            {
                for (int i = 0; i < parameters.Length; i++)
                {
                    object value;
                    Expression arg = call.Arguments[i];
                    ConstantExpression ce = arg as ConstantExpression;
                    if (ce != null)
                    {
                        value = ce.Value;
                    }
                    else
                    {
                        Expression<Func<object>> lambda = Expression.Lambda<Func<object>>(Expression.Convert(arg, typeof(object)), new ParameterExpression[0]);
                        try
                        {
                            value = lambda.Compile()();
                        }
                        catch
                        {
                            value = string.Empty;
                        }
                    }
                    result.Add(parameters[i].Name, value);
                }
            }
            return result;
        }

        public static string BuildUrlFromExpression<TController>(ViewContext context, RouteCollection routeCollection, Expression<Action<TController>> action) where TController : Controller
        {
            RouteValueDictionary values = ExpressionHelper.GetRouteValuesFromExpression<TController>(action);
            VirtualPathData vpd = routeCollection.GetVirtualPath(context.RequestContext, values);
            if (vpd != null)
            {
                return vpd.VirtualPath;
            }
            return null;
        }
    }


}
